from django.shortcuts import render

# Create your views here.
from rest_framework import status

from goods.models import SKU

"""
1.未登录用户的购物车数据保存在cookie中
2.登录用户的购物车数据保存在库中 ，mysql也可以，Redis也可以， 把数据保存在redis中

3.点击加入购物车 需要将 商品id，商品购买数据，是否选中保存起来

4. 设计 如何把数据保存在Redis中

   保存： sku_id,count,selected

   类型： string,hash,list,set,zset

   原则：  Redis的数据是保存在 内存中。 占用越少越好
          满足我们的代码需要

    Hash:
    h_key: {
        key1:value,
        key2:value,
    }

    1: {

        1:5,
    }


    # 单独定义一个 选中的集合
    #需要用程序区判断一下，如果 id，在列表中，表示选中，没有则表示 没有选中
    [1]



    cookie的数据在 浏览器端，怎么保存都可以
    {
        sku_id: {
            count:4,
            selected:True
        }
    }


5.  pickle
    base64

1G = 1024M
1M = 1024Kb
1K = 1024B
1B = 8bit

11000011   10000101    11110000   24bit
    a           b          c


110000          111000      010111          110000
  z                 y           x               l


    base64:



"""

from .serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer
from rest_framework.views import APIView
from django_redis import get_redis_connection
from rest_framework.response import Response
import pickle
import base64
class CartView(APIView):
    """
        # 1.获取user
        # 2.判断是否登录
        # 3.登录用户保存在redis中
        # 4.未登录用户保存在cookie中
        # 5.返回响应

        POST        carts/       增加购物车功能
        """



    # 在运行post之前 系统对token进行了验证
    # 我们先不让系统验证，等我们使用的时候，再验证
    # def perform_authentication(self, request):
    #     pass
    #
    #
    #
    ####################################自己敲的添加到购物车################################
    # def post(self,request):
    #
    #     data=request.data
    #
    #     print(data)
    #     print(type(data))
    #
    #     serializer=CartSerializer(data=data)
    #
    #     serializer.is_valid(raise_exception=True)
    #
    #     sku_id=serializer.data.get('sku_id')
    #     count=serializer.data.get('count')
    #     selected=serializer.data.get('count')
    #
    #
    #
    #     try:
    #         user=request.user
    #     except:
    #         user=None
    #
    #
    #     if user is not None and user.is_authenticated:
    #
    #         redis_conn=get_redis_connection('cart')
    #
    #         redis_conn.hset('cart_%s'%user.id,sku_id,count)
    #
    #         redis_conn.sadd('cart_%s'%user.id,selected)
    #
    #
    #         return Response(serializer.data)
    #
    #
    #
    #
    #
    #     else:
    #         response=Response(serializer.data)
    #
    #
    #         value={sku_id:{
    #             'count':count,
    #             'selected':selected
    #         }}
    #
    #
    #         dumps=pickle.dumps(value)
    #         encode=base64.b64encode(dumps)
    #         cart_str=encode.decode()
    #
    #
    #         response.set_cookie('cart_str',cart_str)
    #
    #         return response







#############################################老师的添加到购物车未优化##########################################

    # def perform_authentication(self, request):
    #     pass
    #
    #
    # def post(self, request):
    #
    #     # 0.获取用户提交的数据(sku_id,count,selected)，并对数据进行校验
    #     data = request.data
    #     serializer = CartSerializer(data=data)
    #     serializer.is_valid(raise_exception=True)
    #
    #     # 获取验证之后的数据，以便 保存到redis或者cookie中
    #     sku_id = serializer.data.get('sku_id')
    #     count = serializer.data.get('count')
    #     selected = serializer.validated_data.get('selected')
    #
    #     # 1.获取user
    #     try:
    #         user = request.user
    #     except Exception as e:
    #         user = None
    #     # 需要使用user的时候 user可能会存在异常，异常我们就认为 user=None
    #
    #     # 2.判断是否登录
    #
    #     # request.user.is_authenticated
    #     # is_authenticated 是否是认证登录用户
    #
    #     if user is not None and user.is_authenticated:
    #         #    3.登录用户保存在redis中
    #
    #         # 3.1连接redis
    #         redis_conn = get_redis_connection('cart')
    #         # 3.2 保存数据
    #
    #         # hash: hash_key: {sku_id:count}
    #         redis_conn.hset('cart_%s' % user.id, sku_id, count)
    #
    #         # set: set_key: [selected_id]
    #         redis_conn.sadd('cart_selected_%s' % user.id, sku_id)
    #
    #         # 3.2 返回响应
    #         return Response(serializer.data)
    #
    #
    #
    #     else:
    #         # 4.未登录用户保存在cookie中
    #         # 可能之前存在cookie数据
    #         # 可能之前不存在cookie数据
    #
    #         # 4.1  先读取之前可能存在的cookie
    #         #
    #         # 4.2 判断
    #
    #
    #
    #         # 暂时没有cookie
    #
    #         # 1.创建响应
    #         response = Response(serializer.data)
    #
    #         # 2. value
    #         """
    #         {
    #             sku_id: {
    #                 count:4,
    #                 selected:True
    #             }
    #         }
    #         """
    #         value = {
    #             sku_id: {
    #                 'count': count,
    #                 'selected': selected
    #             }
    #         }
    #
    #         # 2.1 进行 pickle的处理
    #         dumps = pickle.dumps(value)
    #         # 2.2 进行base64的编码
    #         encode = base64.b64encode(dumps)
    #         # 2.3 将encode的二进制转换为字符串
    #         cart_str = encode.decode()
    #
    #         # 3.设置cookie
    #         response.set_cookie('cart', cart_str)
    #
    #         return response
    #
    #     # 5.返回响应
    #
    #
    #     pass






###############################################优化后的添加到购物车##########################################


    def perform_authentication(self, request):
        pass


    def post(self, request):

        # 0.获取用户提交的数据(sku_id,count,selected)，并对数据进行校验
        data = request.data
        serializer = CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)

        # 获取验证之后的数据，以便 保存到redis或者cookie中
        sku_id = serializer.data.get('sku_id')
        count = serializer.data.get('count')
        selected = serializer.validated_data.get('selected')

        # 1.获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 需要使用user的时候 user可能会存在异常，异常我们就认为 user=None

        # 2.判断是否登录

        # request.user.is_authenticated
        # is_authenticated 是否是认证登录用户

        if user is not None and user.is_authenticated:
            #    3.登录用户保存在redis中

            # 3.1连接redis
            redis_conn = get_redis_connection('cart')
            # 3.2 保存数据
            #
            # # hash: hash_key: {sku_id:count}
            # #无法累加存储
            # # redis_conn.hset('cart_%s' % user.id, sku_id, count)
            #
            # # 可以用累加的方式
            # redis_conn.hincrby('cart_%s' % user.id, sku_id, count)
            # # set: set_key: [selected_id]
            # redis_conn.sadd('cart_selected_%s' % user.id, sku_id)
            #


            # 创建管道(可代替3.2的另一中方法)
            pl=redis_conn.pipeline()

            pl.hincrby('cart_%s' % user.id, sku_id, count)

            pl.sadd('cart_selected_%s' % user.id, sku_id)

            # 让管道去执行
            pl.execute()

            # 3.3 返回响应
            return Response(serializer.data)



        else:
            # 4.未登录用户保存在cookie中
            # 可能之前存在cookie数据
            # 可能之前不存在cookie数据

            # 4.1  先读取之前可能存在的cookie

            cookie_str=request.COOKIES.get('cart')

            # 4.2 判断

            if cookie_str is not None:

                decode=base64.b64decode(cookie_str)

                cart=pickle.loads(decode)

            else:
                cart={}

            # 4.3  判断商品id是否在cookie中存在

            if sku_id in cart:
                ## {1:{count:5,selected:True}}
                # 存在就进行累加
                orginal_count=cart[sku_id]['count']

                count+=orginal_count



            # 4.4 更新数据

            cart[sku_id]={
                'count':count,

                'selected':selected
            }


            # 4.5.设置cookie，返回响应
            response = Response(serializer.data)



            # 进行 pickle的处理
            dumps = pickle.dumps(cart)
            #  进行base64的编码
            encode = base64.b64encode(dumps)
            #  将encode的二进制转换为字符串
            cart_str = encode.decode()

            # 设置cookie
            response.set_cookie('cart', cart_str)


            # 5.返回响应

            return response







#########################################查询购物车数据######################################

    def get(self, request):
        """
        # 1.获取user
        # 2.判断是否登录
        # 3.登录用户保存在redis中
            #连接redis
            #hash {sku_id:count}
            #set [sku_id]
            #最终要获取所有的id 【1,2,3,4,】


        # 4.未登录用户保存在cookie中
            获取cookie数据，进行判断
            如果存在，则获取id   【1,2,3,4】

            【1,2,3,4】
        # 5.根据id获取商品信息     【SKU,SKU,SKU】
        # 6.创建序列化器将对象列表转换为JOSN

        """
        # 1.获取user
        try:
            user = request.user
        except Exception as e:
            user = None
        # 2.判断是否登录
        if user is not None and user.is_authenticated:

            # 3.登录用户保存在redis中
            # 连接redis
            redis_conn = get_redis_connection('cart')
            # hash {sku_id:count}
            sku_count_ids = redis_conn.hgetall('cart_%s' % user.id)
            # set [sku_id]
            sku_selected_ids = redis_conn.smembers('cart_selected_%s' % user.id)

            # 将redis数据结构转换为 cookie结果
            # {1:{count:xx,select:xxx}}

            cart = {}
            for sku_id, count in sku_count_ids.items():
                cart[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in sku_selected_ids
                }



        else:

            # 4.未登录用户保存在cookie中
            # 获取cookie数据，进行判断
            cookie_str = request.COOKIES.get('cart')
            if cookie_str is not None:
                decode = base64.b64decode(cookie_str)
                cart = pickle.loads(decode)
                # {1:{count:xx,select:xxx}}
            else:
                cart = {}


                # 获取id   【1, 2, 3, 4】
        ids = cart.keys()

        # 5.根据id获取商品信息     【SKU,SKU,SKU】
        skus = SKU.objects.filter(pk__in=ids)

        # 我们需要给SKU 传递 count和select数据
        for sku in skus:
            ## {1:{count:xx,select:xxx}}
            # 动态的给属性添加值
            sku.count = cart[sku.id]['count']
            sku.selected = cart[sku.id]['selected']

        # 6.创建序列化器将对象列表转换为JOSN

        serializer = CartSKUSerializer(skus, many=True)

        return Response(serializer.data)




    def put(self,request):

        """
                修改购物车的数据 ： sku_id,count,selected
                                幂等  最终的个数返回给我们，更新之后，我们需要将 个数返回

                #1.获取前端提交的数据
                #2.校验数据
                #3.获取数据
                #4 .获取user
                # 5.判断是否登录
                #6 .登录用户保存在redis中
                    #6.1 连接redis
                    #6.2 修改数据
                    #   hash
                    #   set
                    # 6.3返回响应
                # 7.未登录用户保存在cookie中
                    #7.1 获取cookie数据进行判断
                    #7.2 修改数据
                    #7.3 设置cookie返回响应

                """
        # 1.获取前端提交的数据

        data=request.data

        # 2.校验数据

        serializer=CartSerializer(data=data)
        serializer.is_valid(raise_exception=True)

        # 3.获取数据

        sku_id=serializer.data.get('sku_id')
        count=serializer.data.get('count')
        selected=serializer.data.get('selected')


        #判断用户是否登陆

        try:
            user=request.user
        except:
            user=None


        #登陆
        if user is not None and user.is_authenticated:

            redis_conn=get_redis_connection('cart')

            redis_conn.hset('cart_%s'%user.id,sku_id,count)

            if selected:
                redis_conn.sadd('cart_%s'%user.id,sku_id)
            else:
                redis_conn.srem('cart_%s'%user.id,sku_id)


            return Response(serializer.data)




        # 未登陆
        else:
            # 7.未登录用户保存在cookie中
            # 7.1 获取cookie数据进行判断
            cookie_str=request.COOKIES.get('cart')

            if cookie_str is not None:

                decode=base64.b64decode(cookie_str)
                cart=pickle.loads(decode)


            else:
                cart={}



            if sku_id in cart:

                cart[sku_id]={
                    'count':count,
                    'selected':selected
                }



        response=Response(serializer.data)
        cookie_cart=base64.b64encode(pickle._dumps(cart)).decode()
        response.set_cookie('cart',cookie_cart)

        return response






    def delete(self,request):

        """
                # 1.接受参数
                #2.校验参数
                #3.获取参数
                # 4.获取user
                # 5.判断是否登录
                # 6.登录用户保存在redis中
                    # 连接redis
                    # 删除数据
                    # hash
                    # set
                    #返回响应
                # 7.未登录用户保存在cookie中
                    # 获取cookie数据进判断
                    # 删除数据
                    # 设置cookie返回响应



                """

        # 1.接受参数
        data=request.data

        # 2.校验参数
        serializer=CartDeleteSerializer(data=data)

        serializer.is_valid(raise_exception=True)


        # 3.获取参数

        sku_id=serializer.data.get('sku_id')

        # 4.获取user

        try:
            user=request.user

        except:
            user=None




        # 5.判断是否登录


        if user is not None and user.is_authenticated:

            redis_conn=get_redis_connection('cart')
            # 删除数据
            # hash
            redis_conn.hdel('cart_%s'%user.id,sku_id)
            # set
            redis_conn.srem('cart_selected_%s'%user.id,sku_id)
            # 返回响应

            return Response(status=status.HTTP_204_NO_CONTENT)



        else:
            # 7.未登录用户保存在cookie中
            # 获取cookie数据进判断
            cook_str=request.COOKIES.get('cart')

            if cook_str is not None:
                cart=pickle.loads(base64.b64decode(cook_str))

            else:
                cart={}

            # 删除数据
            if sku_id in cart:

                del cart[sku_id]


            # 设置cookie返回响应
            response=Response(status=status.HTTP_204_NO_CONTENT)

            cookie_cart=base64.b64encode(pickle.dumps(cart)).decode()

            response.set_cookie('cart',cookie_cart)

            return response











